home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Przegladarki internetowe / Mozilla Seamonkey 1.0.5 pl / seamonkey-1.0.5.pl-PL.win32.installer.exe / BROWSER.XPI / bin / chrome / toolkit.jar / content / global / nsDragAndDrop.js < prev    next >
Encoding:
JavaScript  |  2005-07-25  |  14.6 KB  |  388 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is mozilla.org code.
  16.  *
  17.  * The Initial Developer of the Original Code is
  18.  * Netscape Communications Corporation.
  19.  * Portions created by the Initial Developer are Copyright (C) 1998
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *   Ben Goodger <ben@netscape.com> (Original Author)
  24.  *   Pierre Chanial <pierrechanial@netscape.net>
  25.  *
  26.  * Alternatively, the contents of this file may be used under the terms of
  27.  * either of the GNU General Public License Version 2 or later (the "GPL"),
  28.  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29.  * in which case the provisions of the GPL or the LGPL are applicable instead
  30.  * of those above. If you wish to allow use of your version of this file only
  31.  * under the terms of either the GPL or the LGPL, and not to allow others to
  32.  * use your version of this file under the terms of the MPL, indicate your
  33.  * decision by deleting the provisions above and replace them with the notice
  34.  * and other provisions required by the GPL or the LGPL. If you do not delete
  35.  * the provisions above, a recipient may use your version of this file under
  36.  * the terms of any one of the MPL, the GPL or the LGPL.
  37.  *
  38.  * ***** END LICENSE BLOCK ***** */
  39.  
  40. ////////////////////////////////////////////////////////////////////////////
  41. // XXX - WARNING - DRAG AND DROP API CHANGE ALERT - XXX
  42. // This file has been extensively modified in a checkin planned for Mozilla
  43. // 0.8, and the API has been modified. DO NOT MODIFY THIS FILE without 
  44. // approval from ben@netscape.com, otherwise your changes will be lost. 
  45.  
  46. /**
  47.  * XXX - until load is supported in chrome, you also need to include 
  48.  *       these files:
  49.  *       chrome://global/content/nsTransferable.js
  50.  **/
  51.  
  52.  
  53.  
  54. /**
  55.  * nsDragAndDrop - a convenience wrapper for nsTransferable, nsITransferable
  56.  *                 and nsIDragService/nsIDragSession. 
  57.  *
  58.  * Use: map the handler functions to the 'ondraggesture', 'ondragover' and
  59.  *   'ondragdrop' event handlers on your XML element, e.g.                   
  60.  *   <xmlelement ondraggesture="nsDragAndDrop.startDrag(event, observer);"   
  61.  *               ondragover="nsDragAndDrop.startDrag(event, observer);"      
  62.  *               ondragdrop="nsDragAndDrop.drop(event, observer);"/>         
  63.  *                                                                           
  64.  *   You need to create an observer js object with the following member      
  65.  *   functions:                                                              
  66.  *     Object onDragStart (event)        // called when drag initiated,      
  67.  *                                       // returns flavour list with data   
  68.  *                                       // to stuff into transferable      
  69.  *     void onDragOver (Object flavour)  // called when element is dragged   
  70.  *                                       // over, so that it can perform     
  71.  *                                       // any drag-over feedback for provided
  72.  *                                       // flavour                          
  73.  *     void onDrop (Object data)         // formatted data object dropped.   
  74.  *     Object getSupportedFlavours ()    // returns a flavour list so that   
  75.  *                                       // nsTransferable can determine
  76.  *                                       // whether or not to accept drop. 
  77.  **/                                                                  
  78.  
  79. var nsDragAndDrop = {
  80.   
  81.   _mDS: null,
  82.   get mDragService()
  83.     {
  84.       if (!this._mDS) 
  85.         {
  86.           const kDSContractID = "@mozilla.org/widget/dragservice;1";
  87.           const kDSIID = Components.interfaces.nsIDragService;
  88.           this._mDS = Components.classes[kDSContractID].getService(kDSIID);
  89.         }
  90.       return this._mDS;
  91.     },
  92.  
  93.   /**
  94.    * void startDrag (DOMEvent aEvent, Object aDragDropObserver) ;
  95.    *
  96.    * called when a drag on an element is started.
  97.    *
  98.    * @param DOMEvent aEvent
  99.    *        the DOM event fired by the drag init
  100.    * @param Object aDragDropObserver
  101.    *        javascript object of format described above that specifies
  102.    *        the way in which the element responds to drag events.
  103.    **/  
  104.   startDrag: function (aEvent, aDragDropObserver)
  105.     {
  106.       if (!("onDragStart" in aDragDropObserver))
  107.         return;
  108.  
  109.       const kDSIID = Components.interfaces.nsIDragService;
  110.       var dragAction = { action: kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_MOVE + kDSIID.DRAGDROP_ACTION_LINK };
  111.  
  112.       var transferData = { data: null };
  113.       try 
  114.         {
  115.           aDragDropObserver.onDragStart(aEvent, transferData, dragAction);
  116.         }
  117.       catch (e) 
  118.         {
  119.           return;  // not a draggable item, bail!
  120.         }
  121.  
  122.       if (!transferData.data) return;
  123.       transferData = transferData.data;
  124.       
  125.       var transArray = Components.classes["@mozilla.org/supports-array;1"]
  126.                                  .createInstance(Components.interfaces.nsISupportsArray);
  127.  
  128.       var region = null;
  129.       if (aEvent.originalTarget.localName == "treechildren") {
  130.         // let's build the drag region
  131.         var tree = aEvent.originalTarget.parentNode;
  132.         try {
  133.           region = Components.classes["@mozilla.org/gfx/region;1"].createInstance(Components.interfaces.nsIScriptableRegion);
  134.           region.init();
  135.           var obo = tree.treeBoxObject;
  136.           var bo = obo.treeBody.boxObject;
  137.           var sel= tree.view.selection;
  138.  
  139.           var rowX = bo.x;
  140.           var rowY = bo.y;
  141.           var rowHeight = obo.rowHeight;
  142.           var rowWidth = bo.width;
  143.  
  144.           //add a rectangle for each visible selected row
  145.           for (var i = obo.getFirstVisibleRow(); i <= obo.getLastVisibleRow(); i ++)
  146.           {
  147.             if (sel.isSelected(i))
  148.               region.unionRect(rowX, rowY, rowWidth, rowHeight);
  149.             rowY = rowY + rowHeight;
  150.           }
  151.       
  152.           //and finally, clip the result to be sure we don't spill over...
  153.           region.intersectRect(bo.x, bo.y, bo.width, bo.height);
  154.         } catch(ex) {
  155.           dump("Error while building selection region: " + ex + "\n");
  156.           region = null;
  157.         }
  158.       }
  159.  
  160.       var count = 0;
  161.       do 
  162.         {
  163.           var trans = nsTransferable.set(transferData._XferID == "TransferData" 
  164.                                          ? transferData 
  165.                                          : transferData.dataList[count++]);
  166.           transArray.AppendElement(trans.QueryInterface(Components.interfaces.nsISupports));
  167.         }
  168.       while (transferData._XferID == "TransferDataSet" && 
  169.              count < transferData.dataList.length);
  170.       
  171.       try {
  172.         this.mDragService.invokeDragSession(aEvent.target, transArray, region, dragAction.action);
  173.       }
  174.       catch(ex) {
  175.         // this could be because the user pressed escape to
  176.         // cancel the drag. even if it's not, there's not much
  177.         // we can do, so be silent.
  178.       }
  179.       aEvent.preventBubble();
  180.     },
  181.  
  182.   /** 
  183.    * void dragOver (DOMEvent aEvent, Object aDragDropObserver) ;
  184.    *
  185.    * called when a drag passes over this element
  186.    *
  187.    * @param DOMEvent aEvent
  188.    *        the DOM event fired by passing over the element
  189.    * @param Object aDragDropObserver
  190.    *        javascript object of format described above that specifies
  191.    *        the way in which the element responds to drag events.
  192.    **/
  193.   dragOver: function (aEvent, aDragDropObserver)
  194.     { 
  195.       if (!("onDragOver" in aDragDropObserver)) 
  196.         return;
  197.       if (!this.checkCanDrop(aEvent, aDragDropObserver))
  198.         return;
  199.       var flavourSet = aDragDropObserver.getSupportedFlavours();
  200.       for (var flavour in flavourSet.flavourTable)
  201.         {
  202.           if (this.mDragSession.isDataFlavorSupported(flavour))
  203.             {
  204.               aDragDropObserver.onDragOver(aEvent, 
  205.                                            flavourSet.flavourTable[flavour], 
  206.                                            this.mDragSession);
  207.               aEvent.preventBubble();
  208.               break;
  209.             }
  210.         }
  211.     },
  212.  
  213.   mDragSession: null,
  214.  
  215.   /** 
  216.    * void drop (DOMEvent aEvent, Object aDragDropObserver) ;
  217.    *
  218.    * called when the user drops on the element
  219.    *
  220.    * @param DOMEvent aEvent
  221.    *        the DOM event fired by the drop
  222.    * @param Object aDragDropObserver
  223.    *        javascript object of format described above that specifies
  224.    *        the way in which the element responds to drag events.
  225.    **/
  226.   drop: function (aEvent, aDragDropObserver)
  227.     {
  228.       if (!("onDrop" in aDragDropObserver))
  229.         return;
  230.       if (!this.checkCanDrop(aEvent, aDragDropObserver))
  231.         return;  
  232.       if (this.mDragSession.canDrop) {
  233.         var flavourSet = aDragDropObserver.getSupportedFlavours();
  234.         var transferData = nsTransferable.get(flavourSet, this.getDragData, true);
  235.         // hand over to the client to respond to dropped data
  236.         var multiple = "canHandleMultipleItems" in aDragDropObserver && aDragDropObserver.canHandleMultipleItems;
  237.         var dropData = multiple ? transferData : transferData.first.first;
  238.         aDragDropObserver.onDrop(aEvent, dropData, this.mDragSession);
  239.       }
  240.       aEvent.preventBubble();
  241.     },
  242.  
  243.   /** 
  244.    * void dragExit (DOMEvent aEvent, Object aDragDropObserver) ;
  245.    *
  246.    * called when a drag leaves this element
  247.    *
  248.    * @param DOMEvent aEvent
  249.    *        the DOM event fired by leaving the element
  250.    * @param Object aDragDropObserver
  251.    *        javascript object of format described above that specifies
  252.    *        the way in which the element responds to drag events.
  253.    **/
  254.   dragExit: function (aEvent, aDragDropObserver)
  255.     {
  256.       if (!this.checkCanDrop(aEvent, aDragDropObserver))
  257.         return;
  258.       if ("onDragExit" in aDragDropObserver)
  259.         aDragDropObserver.onDragExit(aEvent, this.mDragSession);
  260.     },  
  261.     
  262.   /** 
  263.    * void dragEnter (DOMEvent aEvent, Object aDragDropObserver) ;
  264.    *
  265.    * called when a drag enters in this element
  266.    *
  267.    * @param DOMEvent aEvent
  268.    *        the DOM event fired by entering in the element
  269.    * @param Object aDragDropObserver
  270.    *        javascript object of format described above that specifies
  271.    *        the way in which the element responds to drag events.
  272.    **/
  273.   dragEnter: function (aEvent, aDragDropObserver)
  274.     {
  275.       if (!this.checkCanDrop(aEvent, aDragDropObserver))
  276.         return;
  277.       if ("onDragEnter" in aDragDropObserver)
  278.         aDragDropObserver.onDragEnter(aEvent, this.mDragSession);
  279.     },  
  280.     
  281.   /** 
  282.    * nsISupportsArray getDragData (Object aFlavourList)
  283.    *
  284.    * Creates a nsISupportsArray of all droppable items for the given
  285.    * set of supported flavours.
  286.    * 
  287.    * @param FlavourSet aFlavourSet
  288.    *        formatted flavour list.
  289.    **/  
  290.   getDragData: function (aFlavourSet)
  291.     {
  292.       var supportsArray = Components.classes["@mozilla.org/supports-array;1"]
  293.                                     .createInstance(Components.interfaces.nsISupportsArray);
  294.  
  295.       for (var i = 0; i < nsDragAndDrop.mDragSession.numDropItems; ++i)
  296.         {
  297.           var trans = nsTransferable.createTransferable();
  298.           for (var j = 0; j < aFlavourSet.flavours.length; ++j)
  299.             trans.addDataFlavor(aFlavourSet.flavours[j].contentType);
  300.           nsDragAndDrop.mDragSession.getData(trans, i);
  301.           supportsArray.AppendElement(trans);
  302.         }
  303.       return supportsArray;
  304.     },
  305.  
  306.   /** 
  307.    * Boolean checkCanDrop (DOMEvent aEvent, Object aDragDropObserver) ;
  308.    *
  309.    * Sets the canDrop attribute for the drag session.
  310.    * returns false if there is no current drag session.
  311.    *
  312.    * @param DOMEvent aEvent
  313.    *        the DOM event fired by the drop
  314.    * @param Object aDragDropObserver
  315.    *        javascript object of format described above that specifies
  316.    *        the way in which the element responds to drag events.
  317.    **/
  318.   checkCanDrop: function (aEvent, aDragDropObserver)
  319.     {
  320.       if (!this.mDragSession) 
  321.         this.mDragSession = this.mDragService.getCurrentSession();
  322.       if (!this.mDragSession) 
  323.         return false;
  324.       this.mDragSession.canDrop = this.mDragSession.sourceNode != aEvent.target;
  325.       if ("canDrop" in aDragDropObserver)
  326.         this.mDragSession.canDrop &= aDragDropObserver.canDrop(aEvent, this.mDragSession);
  327.       return true;
  328.     },
  329.  
  330.   /**
  331.    * Do a security check for drag n' drop. Make sure the source document
  332.    * can load the dragged link.
  333.    *
  334.    * @param DOMEvent aEvent
  335.    *        the DOM event fired by leaving the element
  336.    * @param Object aDragDropObserver
  337.    *        javascript object of format described above that specifies
  338.    *        the way in which the element responds to drag events.
  339.    * @param String aUri
  340.    *        the uri being dragged
  341.    **/
  342.   dragDropSecurityCheck: function (aEvent, aDragSession, aUri)
  343.     {
  344.       var sourceDoc = aDragSession.sourceDocument;
  345.  
  346.       if (sourceDoc) {
  347.         // Strip leading and trailing whitespace, then try to create a
  348.         // URI from the dropped string. If that succeeds, we're
  349.         // dropping a URI and we need to do a security check to make
  350.         // sure the source document can load the dropped URI. We don't
  351.         // so much care about creating the real URI here
  352.         // (i.e. encoding differences etc don't matter), we just want
  353.         // to know if aUri really is a URI.
  354.  
  355.         var uriStr = aUri.replace(/^\s*|\s*$/g, '');
  356.         var uri = null;
  357.  
  358.         try {
  359.           uri = Components.classes["@mozilla.org/network/io-service;1"]
  360.             .getService(Components.interfaces.nsIIOService)
  361.             .newURI(uriStr, null, null);
  362.         } catch (e) {
  363.         }
  364.  
  365.         if (uri) {
  366.           // aUri is a URI, do the security check.
  367.           var sourceURI = sourceDoc.documentURI;
  368.  
  369.           const nsIScriptSecurityManager =
  370.             Components.interfaces.nsIScriptSecurityManager;
  371.           var secMan =
  372.             Components.classes["@mozilla.org/scriptsecuritymanager;1"]
  373.             .getService(nsIScriptSecurityManager);
  374.  
  375.           try {
  376.             secMan.checkLoadURIStr(sourceURI, uriStr,
  377.                                    nsIScriptSecurityManager.STANDARD);
  378.           } catch (e) {
  379.             // Stop event propagation right here.
  380.             aEvent.stopPropagation();
  381.  
  382.             throw "Drop of " + aUri + " denied.";
  383.           }
  384.         }
  385.       }
  386.     }
  387. };
  388.